package com.dayatang.exam.domain;

import java.text.NumberFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.hibernate.annotations.CacheConcurrencyStrategy;

import com.dayatang.domain.AbstractEntity;
import com.dayatang.domain.InstanceFactory;

/**
 * 试卷类�?每次考试将为每位考生生成�?��独一无二的试�?
 * 
 * @author yang
 * 
 */
@Entity
@Table(name = "EXAM_PAPERS")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class AnswerPaper extends AbstractEntity implements Comparable<AnswerPaper> {

	private static final long serialVersionUID = -8608009658834740423L;

	/**
	 * 考试�?
	 */
	public static final int STATUS_STARTED = 1;

	/**
	 * 已交�?
	 */
	public static final int STATUS_SUBMITTED = 2;

	/**
	 * 已阅�?
	 */
	public static final int STATUS_SCORED = 3;

	/**
	 * 考生
	 */
	@ManyToOne
	@JoinColumn(name = "USER_ID", nullable = false)
	private User user;

	/**
	 * �?��考试
	 */
	@ManyToOne
	@JoinColumn(name = "EXAM_ID", nullable = false)
	private Exam exam;

	/**
	 * 试卷
	 */
	@ManyToOne
	@JoinColumn(name = "EXAM_ID", nullable = false)
	private AnswerPaper answerPaper;

	/**
	 * 试题相关信息
	 */
	@OneToMany(mappedBy = "answerPaper", cascade = { CascadeType.ALL })
	@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
	private Set<QuestionSolution> solutions = new HashSet<QuestionSolution>();

	/**
	 * 实际�?��时间
	 */
	@Temporal(TemporalType.TIMESTAMP)
	private Date fromTime;

	/**
	 * 实际结束时间
	 */
	@Temporal(TemporalType.TIMESTAMP)
	private Date toTime;

	/**
	 * 交卷时间
	 */
	@Temporal(TemporalType.TIMESTAMP)
	private Date submitTime;

	/**
	 * 阅卷时间
	 */
	@Temporal(TemporalType.TIMESTAMP)
	private Date scoreTime;

	/**
	 * 状�?
	 */
	private int status;

	/**
	 * 总分
	 */
	private int score;

	/**
	 * 单�?题得�?
	 */
	private int singleChoiceScore;

	/**
	 * 多�?题得�?
	 */
	private int multiChoiceScore;

	/**
	 * 判断题得�?
	 */
	private int judgementScore;

	/**
	 * 填空题得�?
	 */
	private int fillBlankScore;

	/**
	 * 问答题得�?
	 */
	private int quizScore;

	/**
	 * 客观题得�?
	 */
	private int objectiveScore;

	/**
	 * 当时�?��机构
	 */
	@ManyToOne
	@JoinColumn(name = "ORGANIZATION_ID")
	private Organization organization;

	/**
	 * 当时�?���?��机构
	 */
	@ManyToOne
	@JoinColumn(name = "TOP_ORGANIZATION_ID")
	private Organization topOrganization;

	/**
	 * 当时�?��次级机构
	 */
	@ManyToOne
	@JoinColumn(name = "SECOND_ORGANIZATION_ID")
	private Organization secondOrganization;

	/**
	 * 当时岗位系列
	 */
	private int positionType;

	/**
	 * 当时岗位级别
	 */
	private int positionLevel;

	/**
	 * 当时岗位
	 */
	private int position;

	public AnswerPaper() {
	}

	public AnswerPaper(Exam exam, User user) {
		this.exam = exam;
		this.user = user;
		organization = user.getOrganization();
		topOrganization = user.getOrganization().getTopOrganization();
		secondOrganization = user.getSecondOrganization();
		positionType = user.getPositionType();
		positionLevel = user.getPositionLevel();
		position = user.getPosition();
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public Exam getExam() {
		return exam;
	}

	public void setExam(Exam exam) {
		this.exam = exam;
	}

	public Set<QuestionSolution> getSolutions() {
		return solutions;
	}

	public void addSolution(QuestionSolution solution) {
		solution.setAnswerPaper(this);
		solutions.add(solution);
	}

	public void addSolutions(Collection<QuestionSolution> solutions) {
		for (QuestionSolution solution : solutions) {
			addSolution(solution);
		}
	}

	public Date getFromTime() {
		return fromTime;
	}

	public void setFromTime(Date fromTime) {
		this.fromTime = fromTime;
	}

	public Date getToTime() {
		return toTime;
	}

	public void setToTime(Date toTime) {
		this.toTime = toTime;
	}

	public Date getSubmitTime() {
		return submitTime;
	}

	public void setSubmitTime(Date submitTime) {
		this.submitTime = submitTime;
	}

	public Date getScoreTime() {
		return scoreTime;
	}

	public void setScoreTime(Date scoreTime) {
		this.scoreTime = scoreTime;
	}

	public int getStatus() {
		return status;
	}

	public void setStatus(int status) {
		this.status = status;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}

	public int getSingleChoiceScore() {
		return singleChoiceScore;
	}

	public void setSingleChoiceScore(int singleChoiceScore) {
		this.singleChoiceScore = singleChoiceScore;
	}

	public int getMultiChoiceScore() {
		return multiChoiceScore;
	}

	public void setMultiChoiceScore(int multiChoiceScore) {
		this.multiChoiceScore = multiChoiceScore;
	}

	public int getJudgementScore() {
		return judgementScore;
	}

	public void setJudgementScore(int judgementScore) {
		this.judgementScore = judgementScore;
	}

	public int getFillBlankScore() {
		return fillBlankScore;
	}

	public void setFillBlankScore(int fillBlankScore) {
		this.fillBlankScore = fillBlankScore;
	}

	public int getQuizScore() {
		return quizScore;
	}

	public void setQuizScore(int quizScore) {
		this.quizScore = quizScore;
	}

	public int getObjectiveScore() {
		return objectiveScore;
	}

	public void setObjectiveScore(int objectiveScore) {
		this.objectiveScore = objectiveScore;
	}

	public Organization getOrganization() {
		return organization;
	}

	public void setOrganization(Organization organization) {
		this.organization = organization;
	}

	public Organization getTopOrganization() {
		return topOrganization;
	}

	public void setTopOrganization(Organization topOrganization) {
		this.topOrganization = topOrganization;
	}

	public Organization getSecondOrganization() {
		return secondOrganization;
	}

	public void setSecondOrganization(Organization secondOrganization) {
		this.secondOrganization = secondOrganization;
	}

	public int getPositionType() {
		return positionType;
	}

	public void setPositionType(int positionType) {
		this.positionType = positionType;
	}

	public int getPositionLevel() {
		return positionLevel;
	}

	public void setPositionLevel(int positionLevel) {
		this.positionLevel = positionLevel;
	}

	public int getPosition() {
		return position;
	}

	public void setPosition(int position) {
		this.position = position;
	}

	/**
	 * 获取题库中指定类型的全部试题
	 * 
	 * @param questionClass
	 *            试题的子类型
	 * @return
	 */
	public <T extends QuestionSolution> List<T> listSolutions(
			Class<T> solutionClass) {
		return QuestionSolution.findByAnswerPaperAndCategory(this, solutionClass);

	}

	/**
	 * 获取单�?题的集合
	 * 
	 * @return
	 */
	public List<SingleChoiceSolution> getSingleChoiceSolutions() {
		return listSolutions(SingleChoiceSolution.class);
	}

	/**
	 * 获取多�?题的集合
	 * 
	 * @return
	 */
	public List<MultiChoiceSolution> getMultiChoiceSolutions() {
		return listSolutions(MultiChoiceSolution.class);
	}

	/**
	 * 获得判断题的集合
	 * 
	 * @return
	 */
	public List<JudgementSolution> getJudgementSolutions() {
		return listSolutions(JudgementSolution.class);
	}

	/**
	 * 获得填空题的集合
	 * 
	 * @return
	 */
	public List<FillBlankSolution> getFillBlankSolutions() {
		return listSolutions(FillBlankSolution.class);
	}

	/**
	 * 获得问答题的集合
	 * 
	 * @return
	 */
	public List<QuizSolution> getQuizSolutions() {
		return listSolutions(QuizSolution.class);
	}

	/**
	 * 获得单�?题的数量
	 * 
	 * @return
	 */
	public int getSingleChoiceCount() {
		return getSingleChoiceSolutions().size();
	}

	/**
	 * 获得多�?题的数量
	 * 
	 * @return
	 */
	public int getMultiChoiceCount() {
		return getMultiChoiceSolutions().size();
	}

	/**
	 * 获得判断题的数量
	 * 
	 * @return
	 */
	public int getJudgementCount() {
		return getJudgementSolutions().size();
	}

	/**
	 * 获得填空题的数量
	 * 
	 * @return
	 */
	public int getFillBlankCount() {
		return getFillBlankSolutions().size();
	}

	/**
	 * 获得问答题的数量
	 * 
	 * @return
	 */
	public int getQuizCount() {
		return getQuizSolutions().size();
	}

	/**
	 * 获得未提交的答题的数�?
	 * 
	 * @param solutionType
	 * @return
	 */
	public int getUnSubmitedQuestionCount(
			Class<? extends QuestionSolution> solutionClass) {
		return getRepository().getUnSubmitedQuestionCount(this,
				solutionClass);
	}

	/**
	 * 获得试卷总分
	 * 
	 * @return
	 */
	public int getPoint() {
		return exam.getPoint();
	}

	public boolean isPassed() {
		return getScore() > exam.getPassPoint();
	}

	public boolean isScored() {
		return status == STATUS_SCORED;
	}

	public boolean isSubmitted() {
		return status == STATUS_SUBMITTED;
	}

	@Override
	public boolean equals(final Object other) {
		if (!(other instanceof AnswerPaper))
			return false;
		AnswerPaper castOther = (AnswerPaper) other;
		return new EqualsBuilder().append(getId(), castOther.getId()).append(user,
				castOther.user).isEquals();
	}

	public int hashCode() {
		return new HashCodeBuilder().append(getId()).append(user).toHashCode();
	}

	public String toString() {
		return new ToStringBuilder(this).append("id", getId()).append("user", user)
				.append("exam", exam).toString();
	}

	public int compareTo(AnswerPaper other) {
		if (other == null) {
			return 1;
		}
		return score > other.getScore() ? -1 : 1;
	}

	private static AnswerPaperRepository repository;

	public static AnswerPaperRepository getRepository() {
		if (repository == null) {
			repository = InstanceFactory.getInstance(AnswerPaperRepository.class);
		}
		return repository;
	}

	public void setRepository(AnswerPaperRepository answerPaperRepository) {
		AnswerPaper.repository = answerPaperRepository;
	}

	public void save() {
		repository.save(this);
	}

	public void remove() {
		repository.remove(this);
	}

	public static AnswerPaper get(Long id) {
		return repository.get(id);
	}

	public static AnswerPaper get(Exam exam, User user) {
		return repository.get(exam, user);
	}

	/**
	 * 按�?试和用户的范例查找试�?
	 * 
	 * @param exam
	 * @param user
	 * @return
	 */
	public static Collection<AnswerPaper> findByExample(Exam exam, User user) {
		return repository.findByExample(exam, user);
	}

	/**
	 * 按�?试和用户查找未批阅的试卷
	 * 
	 * @param exam
	 * @param user
	 * @param organization
	 * @return
	 */
	public static Collection<AnswerPaper> findUnScored(Exam exam, User user,
			Organization organization) {
		return repository.listUnScored(exam, user, organization);
	}

	/**
	 * 列出指定阅卷人能够阅卷的�?��试卷
	 * 
	 * @param currentUser
	 * @return
	 */
	public static Collection<AnswerPaper> findByValuator(User user) {
		return repository.findByValuator(user);
	}

	/**
	 * 查找试卷
	 * 
	 * @param exam
	 *            �?��的�?�?
	 * @param student
	 *            考生
	 * @param organization
	 *            考生单位
	 * @param position
	 *            考生岗位
	 * @return
	 */
	public static Collection<AnswerPaper> find(Exam exam, User student,
			Organization organization, int position) {
		return repository.find(exam, student, organization, position);
	}

	/**
	 * 列出指定用户以往的�?试情�?
	 * 
	 * @param user
	 * @return
	 */
	public static Collection<AnswerPaper> listFinished(User user) {
		return repository.listFinished(user);
	}

	/**
	 * 获取已经阅卷的试�?
	 * 
	 * @return
	 */
	public static Collection<AnswerPaper> listScored(Exam exam) {
		return repository.listScored(exam);
	}

	/**
	 * 获取已提交的试卷
	 * 
	 * @param exam
	 * @return
	 */
	public static Collection<AnswerPaper> listSubmitted(Exam exam) {
		return repository.listSubmitted(exam);
	}

	/**
	 * 考生交卷
	 */
	public void submit() {
		submitTime = Calendar.getInstance().getTime();
		calculateObjectiveScore();
		status = STATUS_SUBMITTED;
		update();
	}

	/**
	 * 计算客观题得�?
	 */
	public void calculateObjectiveScore() {
		singleChoiceScore = 0;
		multiChoiceScore = 0;
		judgementScore = 0;
		for (SingleChoiceSolution solution : getSingleChoiceSolutions()) {
			solution.calculateScore();
			solution.update();
			singleChoiceScore += solution.getScore();
		}
		for (MultiChoiceSolution solution : getMultiChoiceSolutions()) {
			solution.calculateScore();
			solution.update();
			multiChoiceScore += solution.getScore();
		}
		for (JudgementSolution solution : getJudgementSolutions()) {
			solution.calculateScore();
			solution.update();
			judgementScore += solution.getScore();
		}
		objectiveScore = singleChoiceScore + multiChoiceScore + judgementScore;
		score = objectiveScore;
	}

	/**
	 * 阅卷评分
	 */
	public void score() {
		scoreTime = Calendar.getInstance().getTime();
		calculateSubjectiveScore();
		status = STATUS_SCORED;
		update();
	}

	/**
	 * 计算主观题得分和总分
	 */
	public void calculateSubjectiveScore() {
		fillBlankScore = 0;
		quizScore = 0;
		for (FillBlankSolution solution : getFillBlankSolutions()) {
			fillBlankScore += solution.getScore();
		}
		for (QuizSolution solution : getQuizSolutions()) {
			multiChoiceScore += solution.getScore();
		}
		score = objectiveScore + fillBlankScore + quizScore;
	}

	public int getAnswerPaperCountByExam(Exam exam) {
		return repository.getPaperCountOf(exam);
	}

	/**
	 * 获得剩余时间
	 * 
	 * @return
	 */
	public long getRemainSeconds() {
		long result = (toTime.getTime() - System.currentTimeMillis()) / 1000;
		return result > 0 ? result : 0;
	}

	/**
	 * 获得试卷剩余时间(考试监控)
	 * 
	 * @return
	 */
	public long getRemainMinutes() {
		long result = (toTime.getTime() - System.currentTimeMillis()) / 1000 / 60;
		return result > 0 ? result : 0;
	}

	/**
	 * 获得完成�?
	 * 
	 * @return
	 */
	public double getCompletionRate() {
		if (solutions.isEmpty()) {
			return 0;
		}
		return (double) getCompletedQuestionCount() / solutions.size();
	}

	private int getCompletedQuestionCount() {
		return repository.getCompletedQuestionCountOf(this);
	}

	public String getCompletionRatePercent() {
		if (getCompletionRate() >= 1) {
			return 1 * 100 + "%";
		} else {
			return NumberFormat.getPercentInstance()
					.format(getCompletionRate());
		}
	}

	public static Collection<AnswerPaper> findByExam(Exam exam) {
		return null;
	}
	
	public static AnswerPaper create(ExamPaper examPaper, User student) {
		
	}
	
	public static 
}
